package com.atguigu.demojuc.chap04;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

public class UnSafeCollection {

    // ctrl + alt + m  抽取方法
    public static void main(String[] args) {
        //unsafeList();

        //unsafeSet();

        unsafeMap();
    }

    private static void unsafeSet() {
        //1.创建Set集合-HashSet 确保元素不重复,实现天然去重
        // 无序，不能重复，不安全，底层实现：HashMap
        //java.util.ConcurrentModificationException
        //Set<String> set = new HashSet<>(); // 用HashMap的key来存储数据，不能重复；值就是new Object对象。

        //给不安全集合的方法增加了同步代码块：synchronized (mutex) {return list.add(o);}
        //Set<String> set = Collections.synchronizedSet(new HashSet<>());

        //原理：参考CopyOnWriteArrayList
        Set<String> set = new CopyOnWriteArraySet<>();
        //2.循环产生多线程并发对Set集合进行读写操作
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(set);
            }).start();
        }
    }

    private static void unsafeMap() {
        //1.创建Map集合-HashMap
        //键值对形式存储数据；    底层数据结构：数组 + 链表/红黑树
        // 初始容量 16  扩容： 2倍     加载因子：0.75      不同的key经过hash函数计算，可能得到同一个索引位置，那么就会出现冲突问题！
        //解决冲突问题： 链式法
        // 链表 或 红黑树       链表元素大于8并且容器64转树；    小于等于6树转链表
        //java.util.ConcurrentModificationException
        //Map<String, String> map = new HashMap<>();
        //1.1 使用HashTable线程安全集合类
        //Map<String, String> map = new Hashtable<>(); //方法加了synchronized
        //1.2 通过集合工具类产生线程安全集合
        //Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
        //1.3 使用ConcurrentHashMap线程安全集合类
        Map<String, String> map = new ConcurrentHashMap<>(); //  推荐使用   分段锁
        //2.循环产生多线程并发对Map集合进行读写操作
        for (int i = 0; i < 30; i++) {
            int finalI = i;
            new Thread(() -> {
                //2.1 新增元素
                map.put(finalI + "", UUID.randomUUID().toString());
                //2.2 打印集合元素
                System.out.println(map);
            }).start();
        }
    }


    /**
     * 测试List集合线程安全
     */
    private static void unsafeList() {
        //1.声明List集合对象
        //有序 可重复 不安全 效率高（不用加锁） 底层数据结构：数组  初始容量大小 10  扩容 原数组1.5倍   有界
        //插入和删除慢  修改和获取快    遍历慢
        //java.util.ConcurrentModificationException
        //List<String> list = new ArrayList<>();

        //有序 可重复 不安全 效率高（不用加锁）  底层数据结构：链表     不需要扩容 无界
        //插入和删除快  修改和获取慢    遍历慢
        //List<String> list = new LinkedList<>();

        //1.1 提供线程安全List集合
        //有序 可重复 安全 效率低（加锁） 底层数据结构：数组  初始容量大小 10  扩容 原数组2倍   有界
        //插入和删除慢  修改和获取快    遍历慢
        //List<String> list = new Vector<>(); //迭代方法也加synchronized

        //1.2 通过集合工具类产生线程安全集合  Map,Set都提供线程安全类
        //list instanceof RandomAccess ?
        //                new SynchronizedRandomAccessList<>(list) :
        //                new SynchronizedList<>(list)
        //给不安全集合的方法增加了同步代码块：synchronized (mutex) {return list.add(o);}
        // iterator()  迭代方法不是线程安全的。
        //List<String> list = Collections.synchronizedList(new ArrayList<>());

        //1.3 通过写时复制容器创建线程安全集合
        //通过写时复制技术，实现线程安全。原理：将原来旧集合复制一份，长度+1, 写数据时往新集合中写；读数据可以从旧集合中读。 写和读是并发的，是安全的。思想：读写分离思想。
        //优点：读写可并发。缺点：数据不一致，2倍空间。
        List<String> list = new CopyOnWriteArrayList<>();
        //2.开启多线程对list集合进行读写操作
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                //2.1 将随机字符串加入集合
                list.add(UUID.randomUUID().toString());
                //2.2 将集合中进行输出打印 调用对象.toString方法
                System.out.println(list);
            }).start();
        }
    }
}